/**
 * Timings with crystal oscillator 32768 Hz:
 *   bus clock: 7340032 Hz
 *   I2C: 101945 Hz
 */     

#include <io08GB60.h>

#define NULL 0
typedef unsigned char ui8;

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

void main (void) 
{      
	// system initialization
	SOPT = 34;
	SPMSC1 = 20;
	SPMSC2 = 0;
	ICGC1 = 56;
	ICGC2 = 217;
	while (!(ICGS1 & 8));                  
	FSTAT = 16;
	PTFDD = 0xff;
	IICC = 0;

	// modulo for 64 Hz interrupt
	TPM2MODH = (2*448) / 256;
	TPM2MODL = (2*448) & 0xff;

	// counter driven by bus clock, enable interrupt, prescale 128
	TPM2SC = 8 | 64 | 4 | 2 | 1;
    
	while (1) asm("wait");
}

static void delayLoop(int n)
{
	int i;
	for (i = 0; i < n; i++) asm("nop");
}

ui8 g_state = 0;
ui8 g_counter = 0;

static void stopI2C()
{
	// send stop bit and disable I2C
	IICC = 128 | 16;
    delayLoop(5);
	IICC = 0;
}

ui8 g_i2cState = 0;
ui8 test = 0;

#pragma interrupt_handler i2cInterrupt
void i2cInterrupt(void)
{
	// get state
	ui8 state = IICS;
	
	// clear IICIF	
	IICS = 2;
	  
	// wait until transfer complete
	if (!(state & 0x80)) return;

	// send next ui8 or stop bit
    switch (g_i2cState) {
		case 0:  // write config command
        	IICD = 7;
            break;
		case 1:  // write config data
        	IICD = 0;
            break;
		case 2:  // send start, stop and address 
			IICC = 128 | 64 | 16;  // stop
            delayLoop(5);
			IICC = 128 | 64 | 32 | 16;  // start
			IICS = 2;
			IICD = 0x26 << 1;
            break;
		case 3:  // write port 1 out command
        	IICD = 3;
            break;
		case 4:  // write data to port 1
        	IICD = test;
            break;
		case 5:  // send start, stop and address 
			IICC = 128 | 64 | 16;  // stop
            delayLoop(5);
			IICC = 128 | 64 | 32 | 16;  // start
			IICS = 2;
			IICD = 0x26 << 1;
            break;
		case 6:  // write read port 0 command
        	IICD = 0;
            break;
		case 7:  // send repeated start and address with read mode bit
			IICC = 128 | 64 | 32 | 16 | 4;
			IICD = (0x26 << 1) | 1;
            break;
		case 8:  // switch to read mode
			IICC = 128 | 64 | 32 | 8;  // receive mode
            state = IICD;  // dummy read to start read process
            break;
		case 9:  // display the received byte and stop I2C
        	PTFD = IICD;
			IICC = 0;
            break;
	}
    g_i2cState++;
}

#pragma interrupt_handler timerInterrupt
void timerInterrupt(void) 
{
	// clear interrupt flag
	TPM2SC = TPM2SC & 0x7f;

	// start I2C
	IICF = 0x13;
	IICC = 128 | 64 | 16;
	IICC = 128 | 64 | 32 | 16;
	IICS = 2;
    g_i2cState = 0;
	IICD = 0x26 << 1;

    // increment counter with 8 Hz
    if (g_counter > 0) {
    	g_counter--;
    } else {
    	g_counter = 8;
        test++;
	}
}

#pragma abs_address:0xffc0
void (* const _vectab[])(void) = {
	 NULL,  // Unused Vector
	 NULL,  // Unused Vector
	 NULL,  // Unused Vector
	 NULL,  // Unused Vector
	 NULL,  // Unused Vector
	 NULL,  // Unused Vector
	 NULL,  // Real-time interrupt
	 i2cInterrupt,  // IIC control
	 NULL,  // AD conversion complete
	 NULL,  // Keyboard pins
	 NULL,  // SCI2 transmit
	 NULL,  // SCI2 receive
	 NULL,  // SCI2 error
	 NULL,  // SCI1 transmit
	 NULL,  // SCI1 receive
	 NULL,  // SCI1 error
	 NULL,  // SPI
	 timerInterrupt,  // TPM2 overflow
	 NULL,  // TPM2 channel 4
	 NULL,  // TPM2 channel 3
	 NULL,  // TPM2 channel 2
	 NULL,  // TPM2 channel 1
	 NULL,  // TPM2 channel 0
	 NULL,  // TPM1 overflow 
	 NULL,  // TPM1 channel 2
	 NULL,  // TPM1 channel 1
	 NULL,  // TPM1 channel 0
	 NULL,  // ICG
	 NULL,  // Low-voltage detect
	 NULL,  // IRQ pin
	 NULL,  // Software interrupt
	 
/*	RESET defined in crt08.o */
	};
#pragma end_abs_address

